package com.example.android.google.apis.com.example.android.apis;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutionException;

import persistence.DataBaseController;
import utils.DataDownloader;
import utils.HTML;
import utils.MainActivity;
import utils.ShowException;
import utils.UpdateMap;
import views.BalloonItemizedOverlay;
import views.DialogLauncher;
import views.MapDirections;
import views.MyBalloonItemizedOverlay;
import views.MyOverlay;

import com.example.android.google.apis.R;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
import com.google.android.maps.Projection;

import docks.Dock;
import docks.DockController;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.widget.Toast;

public class MapsDemo extends MapActivity implements LocationListener {

    public static final int DIALOG_KEY = 1;

    public static final int ONE_ID = Menu.FIRST;
    public static final int TWO_ID = Menu.FIRST + 1;
    public static final int THREE_ID = Menu.FIRST + 2;
    public static final int FOUR_ID = Menu.FIRST + 3;
    public static final int FIVE_ID = Menu.FIRST + 4;
    public static final int SIX_ID = Menu.FIRST + 5;

    private ProgressDialog pd;
    private MapView map = null;
    private MyLocationOverlay me = null;

    public void onCreate(Bundle savedInstanceState) {

	super.onCreate(savedInstanceState);

	requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
	setContentView(R.layout.maps);
	getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.banner);
	map = (MapView) findViewById(R.id.map);

	// Setting up static classes
	DialogLauncher.setActivity(this);
	DialogLauncher.setId(DIALOG_KEY);
	MainActivity.setActivity(this);
	UpdateMap.setMap(this);
	DataDownloader.setContext(this);

	Log.v("gBicing", "Init app");

	// Create DataBase
	try {

	    DataBaseController.getInstance().initDatabase(this);

	} catch (Exception e) {

	    ShowException.show(this, e);
	}

	// Reloading data
	if (getIntent().getExtras() == null) {

	    DialogLauncher.launchDialog();
	    DownloadBicingData dbd = new DownloadBicingData();
	    dbd.execute();
	}

	Log.v("gBicing", "Database created");

	Drawable[] markers = new Drawable[6];

	Drawable markerGreen 		= getResources().getDrawable(R.drawable.greenpin);
	Drawable markerOrange		= getResources().getDrawable(R.drawable.orangepin);
	Drawable markerRed 		= getResources().getDrawable(R.drawable.redpin);
	Drawable glowingMarkerGreen 	= getResources().getDrawable(R.drawable.positiongreenstar);
	Drawable glowingMarkerOrange 	= getResources().getDrawable(R.drawable.positionorangestar);
	Drawable glowingMarkerRed 	= getResources().getDrawable(R.drawable.positionredstar);

	markerGreen.setBounds(0, 0, markerGreen.getIntrinsicWidth(),
		markerGreen.getIntrinsicHeight());
	markerOrange.setBounds(0, 0, markerOrange.getIntrinsicWidth(),
		markerOrange.getIntrinsicHeight());
	markerRed.setBounds(0, 0, markerRed.getIntrinsicWidth(),
		markerRed.getIntrinsicHeight());
	glowingMarkerGreen.setBounds(0, 0,
		glowingMarkerGreen.getIntrinsicWidth(),
		glowingMarkerGreen.getIntrinsicHeight());
	glowingMarkerOrange.setBounds(0, 0,
		glowingMarkerOrange.getIntrinsicWidth(),
		glowingMarkerOrange.getIntrinsicHeight());
	glowingMarkerRed.setBounds(0, 0, glowingMarkerRed.getIntrinsicWidth(),
		glowingMarkerRed.getIntrinsicHeight());

	markers[0] = markerGreen;
	markers[1] = markerOrange;
	markers[2] = markerRed;
	markers[3] = glowingMarkerGreen;
	markers[4] = glowingMarkerOrange;
	markers[5] = glowingMarkerRed;

	me = new MyLocationOverlay(this, map);
	map.getOverlays().add(0,
		new MyBalloonItemizedOverlay(markerOrange, map, markers));
	map.getOverlays().add(1, me);

	MapView mapView = (MapView) findViewById(R.id.map);
	// habilitamos el control de zoom
	mapView.setBuiltInZoomControls(true);

	LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

	Location lastLoc = locationManager
		.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

	GeoPoint p;

	p = getPoint(lastLoc.getLatitude(), lastLoc.getLongitude());

	map.getController().animateTo(p);
	map.getController().setZoom(17);

	// updateLocation(locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER));
	/*
	 * se actualizar� cada minuto y 50 metros de cambio en la localizaci�n
	 * mientras m�s peque�os sean estos valores m�s frecuentes ser�n las
	 * actualizaciones
	 */
	locationManager.requestLocationUpdates(
		LocationManager.NETWORK_PROVIDER, 6000, 50, this);
	locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
		6000, 50, this);

	// dismissDialog(DIALOG_KEY);
    }

    @Override
    public void onResume() {

	me.enableCompass();
	me.enableMyLocation();

	Bundle b = getIntent().getExtras();
	if (b != null) {

	    if (b.getBoolean("moveToDock")) {

		MapView mapView = (MapView) findViewById(R.id.map);
		MapController mapController = mapView.getController();
		GeoPoint p = getPoint(b.getDouble("longitude"),
			b.getDouble("latitude"));
		
		mapController.animateTo(p);

		Overlay over = (MyBalloonItemizedOverlay) mapView.getOverlays()
			.get(0);
		over.onTap(p, mapView);

		getIntent().putExtra("moveToDock", false);
	    }
	}

	super.onResume();
    }

    @Override
    public void onPause() {
	super.onPause();
	me.disableCompass();
	// me.disableMyLocation();
    }

    @Override
    protected boolean isRouteDisplayed() {
	return (false);
    }

    @Override
    protected void onDestroy() {

	DataBaseController.getInstance().closeDatabase();
	super.onDestroy();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
	if (keyCode == KeyEvent.KEYCODE_S) {
	    map.setSatellite(!map.isSatellite());
	    return (true);
	} else if (keyCode == KeyEvent.KEYCODE_Z) {
	    map.displayZoomControls(true);
	    return (true);
	}
	return (super.onKeyDown(keyCode, event));
    }

    private GeoPoint getPoint(double lat, double lon) {
	return (new GeoPoint((int) (lat * 1000000.0), (int) (lon * 1000000.0)));
    }

    // MENU
    public boolean onCreateOptionsMenu(Menu menu) {
	populateMenu(menu);
	return (super.onCreateOptionsMenu(menu));
    }

    private void populateMenu(Menu menu) {

	menu.add(Menu.NONE, ONE_ID, Menu.NONE, "Refresh").setIcon(
		getResources().getDrawable(R.drawable.ic_menu_refresh));
	menu.add(Menu.NONE, TWO_ID, Menu.NONE, "Where am I?").setIcon(
		getResources().getDrawable(R.drawable.ic_menu_center));
	menu.add(Menu.NONE, THREE_ID, Menu.NONE, "Dock list").setIcon(
		getResources().getDrawable(R.drawable.ic_menu_list2));
	menu.add(Menu.NONE, FOUR_ID, Menu.NONE, "Phone incident").setIcon(
		getResources().getDrawable(R.drawable.ic_menu_phone));
	menu.add(Menu.NONE, FIVE_ID, Menu.NONE, "Park bike").setIcon(
		getResources().getDrawable(R.drawable.ic_menu_exit));
	menu.add(Menu.NONE, SIX_ID, Menu.NONE, "Get a bike").setIcon(
			getResources().getDrawable(R.drawable.ic_menu_exit));
    }

    public boolean onOptionsItemSelected(MenuItem item) {
	return (applyMenuChoice(item) || super.onOptionsItemSelected(item));
    }

    private boolean applyMenuChoice(MenuItem item) {

	Intent intent;
	LocationManager locationManag;
	Location locat;
	GeoPoint its_me;
	Dock closest;
	MyOverlay mo;
	
	switch (item.getItemId()) {
	case ONE_ID:

	    DialogLauncher.launchDialog();
	    DownloadBicingData dbd = new DownloadBicingData();
	    dbd.execute();
	    return (true);

	case TWO_ID:

	    MapView mapView = (MapView) findViewById(R.id.map);
	    MapController mapController = mapView.getController();
	    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
	    Location loc = locationManager
		    .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
	    GeoPoint p = getPoint(loc.getLatitude(), loc.getLongitude());
	    mapController.animateTo(p);
	    mapController.setZoom(17);
	    return (true);

	case THREE_ID:

	    intent = new Intent(MapsDemo.this, views.DockTab.class);
	    startActivity(intent);
	    return (true);

	case FOUR_ID:

	    startActivity(new Intent(Intent.ACTION_DIAL,
		    Uri.parse("tel:900315531")));
	    return (true);

	case FIVE_ID:

	    locationManag = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
	    locat = locationManag
		    .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
	    its_me = getPoint(locat.getLatitude(),
		    locat.getLongitude());
	    closest = DockController.getInstance().getClosestDockToPark(
		    its_me);

	    intent = new Intent(MapsDemo.this, MapDirections.class);

	    intent.putExtra("me_lat", locat.getLatitude());
	    intent.putExtra("me_lon", locat.getLongitude());

	    intent.putExtra("dest_lat", closest.getLatitude());
	    intent.putExtra("dest_lon", closest.getLongitude());
	    
	    mo = new MyOverlay();
	    mo.setOverlay(me);
	    intent.putExtra("me_overlay", mo);

	    startActivity(intent);

	    // Toast.makeText(
	    // this,
	    // "The closest dock is... " + closest.getIdDock() + " - "
	    // + closest.getAddress(), Toast.LENGTH_LONG).show();
	    
	case SIX_ID:
		
	    locationManag = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
	    locat = locationManag
		    .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
	    its_me = getPoint(locat.getLatitude(),
		    locat.getLongitude());
	    closest = DockController.getInstance().getClosesDockToPickUp(
		    its_me);

	    intent = new Intent(MapsDemo.this, MapDirections.class);

	    intent.putExtra("me_lat", locat.getLatitude());
	    intent.putExtra("me_lon", locat.getLongitude());

	    intent.putExtra("dest_lat", closest.getLatitude());
	    intent.putExtra("dest_lon", closest.getLongitude());
	    
	    mo = new MyOverlay();
	    mo.setOverlay(me);
	    intent.putExtra("me_overlay", mo);

	    startActivity(intent);
	}

	return (false);
    }

    public boolean onContextItemSelected(MenuItem item) {
	return (applyMenuChoice(item) || super.onContextItemSelected(item));
    }

    @Override
    public void onLocationChanged(Location location) {

	MapView mapView = (MapView) findViewById(R.id.map);
	List<Overlay> mapOverlays = mapView.getOverlays();
	if (mapOverlays.get(1) != null)
	    mapOverlays.remove(1);
	// me = new MyLocationOverlay(this, map);
	map.getOverlays().add(1, me);
	mapView.invalidate();

	// updateLocation(location);
    }

    @Override
    public void onProviderDisabled(String provider) {

	// Intent intent = new Intent(
	// android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
	// startActivity(intent);
    }

    @Override
    public void onProviderEnabled(String provider) {
	// TODO Auto-generated method stub

    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
	// TODO Auto-generated method stub

    }

    @Override
    protected Dialog onCreateDialog(int id) {

	switch (id) {

	case DIALOG_KEY:
	    
	    ProgressDialog dialog = new ProgressDialog(this);
	    dialog.setTitle("gBicing");
	    dialog.setMessage("Loading Bicing data, please wait...");
	    dialog.setCancelable(false);
	    return dialog;
	}
	return null;
    }

    public void updateOverlays() {

	Drawable[] markers = new Drawable[6];

	Drawable markerGreen = getResources().getDrawable(R.drawable.greenpin);
	Drawable markerOrange = getResources()
		.getDrawable(R.drawable.orangepin);
	Drawable markerRed = getResources().getDrawable(R.drawable.redpin);
	Drawable glowingMarkerGreen = getResources().getDrawable(
		R.drawable.positiongreenstar);
	Drawable glowingMarkerOrange = getResources().getDrawable(
		R.drawable.positionorangestar);
	Drawable glowingMarkerRed = getResources().getDrawable(
		R.drawable.positionredstar);

	markerGreen.setBounds(0, 0, markerGreen.getIntrinsicWidth(),
		markerGreen.getIntrinsicHeight());
	markerOrange.setBounds(0, 0, markerOrange.getIntrinsicWidth(),
		markerOrange.getIntrinsicHeight());
	markerRed.setBounds(0, 0, markerRed.getIntrinsicWidth(),
		markerRed.getIntrinsicHeight());
	glowingMarkerGreen.setBounds(0, 0,
		glowingMarkerGreen.getIntrinsicWidth(),
		glowingMarkerGreen.getIntrinsicHeight());
	glowingMarkerOrange.setBounds(0, 0,
		glowingMarkerOrange.getIntrinsicWidth(),
		glowingMarkerOrange.getIntrinsicHeight());
	glowingMarkerRed.setBounds(0, 0, glowingMarkerRed.getIntrinsicWidth(),
		glowingMarkerRed.getIntrinsicHeight());

	markers[0] = markerGreen;
	markers[1] = markerOrange;
	markers[2] = markerRed;
	markers[3] = glowingMarkerGreen;
	markers[4] = glowingMarkerOrange;
	markers[5] = glowingMarkerRed;

	map.getOverlays().remove(0);
	map.invalidate();
	map.refreshDrawableState();
	map.getOverlays().add(0,
		new MyBalloonItemizedOverlay(markerOrange, map, markers));
	map.invalidate();
	map.refreshDrawableState();
    }

    private class DownloadBicingData extends
	    AsyncTask<Void, Void, Hashtable<Integer, Dock>> {

	@Override
	protected Hashtable<Integer, Dock> doInBackground(Void... arg0) {

	    Hashtable<Integer, Dock> list = null;

	    try {
		// showDialog(DIALOG_KEY);
		String html = HTML
			.doConnection("http://www.bicing.cat/localizaciones/localizaciones.php?TU5fTE9DQUxJWkFDSU9ORVM%3D&MQ%3D%3D");
		String xml = HTML.extractXml(html, "<Document>", "</Document>");
		xmlparser.SaxParser sax = new xmlparser.SaxParser(xml);
		sax.parseBicingState();
		list = sax.getDockList();
		// dismissDialog(DIALOG_KEY);
	    } catch (Exception e) {

		Log.v("CHIVATO", "CONNECTION ERROOOOOOOR!!!");
		return null;
	    }

	    return list;
	}

	@Override
	protected void onPreExecute() {

	    DialogLauncher.launchDialog();
	    // showDialog(DIALOG_KEY);
	}

	@Override
	protected void onPostExecute(Hashtable<Integer, Dock> hash) {

	    // pd.dismiss();

	    if (hash == null) {

		Log.v("CHIVATO", "HASH IS NULL YOU STUPID JERK!!");
		AlertDialog alert = new AlertDialog.Builder(MapsDemo.this)
			.create();
		alert.setTitle("Connection error");
		alert.setMessage("It seems there has been a connection problem.");
		alert.setButton("Try again",
			new DialogInterface.OnClickListener() {

			    @Override
			    public void onClick(DialogInterface dialog,
				    int which) {

				DownloadBicingData dbd = new DownloadBicingData();
				dbd.execute();
			    }

			});

		alert.setButton2("Cancel",
			new DialogInterface.OnClickListener() {

			    @Override
			    public void onClick(DialogInterface dialog,
				    int which) {
				return;
			    }
			});
		alert.show();
	    } else {

		Log.v("CHIVATO", "HASH IS NOT NULL");
		DockController.getInstance().refreshDockData(hash);

		updateOverlays();
	    }
	    DialogLauncher.dismissDialog();
	    // map.postInvalidate();
	    // map.invalidate();
	    // map.refreshDrawableState();
	}

    }
}